import SockJS from 'sockjs-client'
import { Client } from '@stomp/stompjs'

/**
 * WebSocket 连接管理类
 */
class WebSocketManager {
  constructor() {
    this.client = null
    this.connected = false
    this.reconnectAttempts = 0
    this.maxReconnectAttempts = 3
    this.reconnectDelay = 3000
    this.messageHandlers = []
    this.connectPromise = null
  }

  /**
   * 连接 WebSocket
   * @param {String} token JWT Token
   * @returns {Promise}
   */
  connect(token) {
    if (this.connected) {
      console.log('WebSocket 已连接')
      return Promise.resolve()
    }

    if (this.connectPromise) {
      return this.connectPromise
    }

    this.connectPromise = new Promise((resolve, reject) => {
      try {
        // 创建 SockJS 连接，传递 token 参数
        const socket = new SockJS(import.meta.env.VITE_API_BASE_URL + '/ws?token=' + encodeURIComponent(token))

        // 创建 STOMP 客户端
        this.client = new Client({
          webSocketFactory: () => socket,

          // 启用调试日志
          debug: (str) => {
            console.log('STOMP Debug:', str)
          },

          // 连接成功回调
          onConnect: (frame) => {
            console.log('✅ WebSocket 连接成功', frame)
            this.connected = true
            this.reconnectAttempts = 0
            this.connectPromise = null

            // 订阅个人消息队列
            this.subscribeToNotifications(token)

            resolve()
          },

          // 连接失败回调
          onStompError: (frame) => {
            console.error('WebSocket 连接错误', frame)
            this.connected = false
            this.connectPromise = null
            
            // 尝试重连
            this.attemptReconnect(token)
            
            reject(new Error('WebSocket 连接失败'))
          },

          // WebSocket 关闭回调
          onWebSocketClose: () => {
            console.log('WebSocket 连接关闭')
            this.connected = false
            this.connectPromise = null
            
            // 尝试重连
            this.attemptReconnect(token)
          },

          // 心跳设置
          heartbeatIncoming: 10000,
          heartbeatOutgoing: 10000,

          // 调试日志
          debug: (str) => {
            // console.log('STOMP Debug:', str)
          }
        })

        // 激活连接
        this.client.activate()
      } catch (error) {
        console.error('创建 WebSocket 连接失败', error)
        this.connectPromise = null
        reject(error)
      }
    })

    return this.connectPromise
  }

  /**
   * 订阅通知消息
   * @param {String} token JWT Token
   */
  subscribeToNotifications(token) {
    if (!this.client || !this.connected) {
      console.error('❌ WebSocket 未连接，无法订阅')
      return
    }

    try {
      // 从 token 中提取用户ID
      const userId = this.getUserIdFromToken(token)
      console.log('📝 当前用户ID:', userId)

      // 订阅个人消息队列
      // 注意：使用 /user/queue/notifications 而不是 /user/{userId}/queue/notifications
      // Spring 会自动将消息路由到当前用户的 session
      const subscription = this.client.subscribe('/user/queue/notifications', (message) => {
        try {
          const notification = JSON.parse(message.body)
          console.log('📨 收到通知消息', notification)

          // 触发所有消息处理器
          console.log('📢 当前消息处理器数量:', this.messageHandlers.length)
          this.messageHandlers.forEach((handler, index) => {
            try {
              console.log(`🔔 执行消息处理器 ${index + 1}`)
              handler(notification)
            } catch (error) {
              console.error('❌ 消息处理器执行失败', error)
            }
          })
        } catch (error) {
          console.error('❌ 解析通知消息失败', error)
        }
      })

      console.log(`✅ 已订阅通知队列：/user/queue/notifications (用户ID: ${userId})`)
      console.log('📋 订阅对象:', subscription)
    } catch (error) {
      console.error('❌ 订阅通知失败', error)
    }
  }

  /**
   * 从 Token 中提取用户ID
   * @param {String} token JWT Token
   * @returns {String} 用户ID
   */
  getUserIdFromToken(token) {
    try {
      const payload = token.split('.')[1]
      const decoded = JSON.parse(atob(payload))
      return decoded.userId || decoded.sub
    } catch (error) {
      console.error('解析 Token 失败', error)
      return null
    }
  }

  /**
   * 尝试重连
   * @param {String} token JWT Token
   */
  attemptReconnect(token) {
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.error('WebSocket 重连次数已达上限，停止重连')
      return
    }

    this.reconnectAttempts++
    console.log(`WebSocket 将在 ${this.reconnectDelay}ms 后尝试第 ${this.reconnectAttempts} 次重连`)

    setTimeout(() => {
      console.log(`开始第 ${this.reconnectAttempts} 次重连`)
      this.connect(token).catch(error => {
        console.error('重连失败', error)
      })
    }, this.reconnectDelay)
  }

  /**
   * 添加消息处理器
   * @param {Function} handler 消息处理函数
   */
  onMessage(handler) {
    if (typeof handler === 'function') {
      this.messageHandlers.push(handler)
      console.log('✅ 添加消息处理器，当前处理器数量:', this.messageHandlers.length)
      console.log('📋 处理器列表:', this.messageHandlers)
    }
  }

  /**
   * 移除消息处理器
   * @param {Function} handler 消息处理函数
   */
  offMessage(handler) {
    const index = this.messageHandlers.indexOf(handler)
    if (index > -1) {
      this.messageHandlers.splice(index, 1)
    }
  }

  /**
   * 发送消息
   * @param {String} destination 目标地址
   * @param {Object} body 消息体
   */
  send(destination, body) {
    if (!this.client || !this.connected) {
      console.error('WebSocket 未连接，无法发送消息')
      return
    }

    try {
      this.client.publish({
        destination,
        body: JSON.stringify(body)
      })
      console.log('消息发送成功', destination, body)
    } catch (error) {
      console.error('发送消息失败', error)
    }
  }

  /**
   * 断开连接
   */
  disconnect() {
    if (this.client) {
      try {
        this.client.deactivate()
        console.log('WebSocket 已断开')
      } catch (error) {
        console.error('断开 WebSocket 失败', error)
      }
    }
    
    this.connected = false
    this.client = null
    this.messageHandlers = []
    this.reconnectAttempts = 0
    this.connectPromise = null
  }

  /**
   * 检查连接状态
   * @returns {Boolean}
   */
  isConnected() {
    return this.connected
  }
}

// 导出单例
export default new WebSocketManager()

